package com.atguigu.government.sqlparser;

import com.atguigu.government.bean.SourceTarget;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

import java.util.ArrayList;
import java.util.List;

/**
 * 获取各个顶点（输入、输出表）
 * 获取边（各个顶点的关系）
 *
 * HQL将sql翻译成MR任务：
 * 1.词法分析 --- 将SQL分词转成标记流
 * 2.语法分析 --- Antlr4 框架是一个语法解析器，转成 抽象语法树 AST    javacc:calcite(flink sql)  Antlr4:hive sql/spark sql
 * 3.语义分析(类型检查) --- 翻译成操作树 / 执行计划
 * 4.汇编(mysql)/MR/Flink底层API程序  将特定的语法规则转换成代码
 */
public class TableLineageImpl extends SQLBaseVisitor<Object> {
    //输入表的表名组成的列表
    private final List<String> inputTables = new ArrayList<>();
    //输出表的表名
    private String outputTable;

    @Override
    public Object visitInsertStatement(SQLParser.InsertStatementContext ctx) {
        //提前输出表的表名
        outputTable = ctx.T_QIDENTIFIER().getText();
        return super.visitInsertStatement(ctx);
    }

    @Override
    public Object visitFromClause(SQLParser.FromClauseContext ctx) {
        //提前输入表的表名
        inputTables.add(ctx.T_QIDENTIFIER().getText());
        return super.visitFromClause(ctx);
    }

    @Override
    public Object visitJoinClause(SQLParser.JoinClauseContext ctx) {
        //提前输入表的表名
        inputTables.add(ctx.T_QIDENTIFIER().getText());
        return super.visitJoinClause(ctx);
    }

    //返回边(顶点的关系)
    public static List<SourceTarget> lineage(String sql) {
        var stream = CharStreams.fromString(sql);
        var lexer = new SQLLexer(stream);  //词法分析器
        var tokens = new CommonTokenStream(lexer);
        var parser = new SQLParser(tokens);  //语法分析器
        var ast = parser.statement();
        var tableLineage = new TableLineageImpl();
        tableLineage.visit(ast);

        //边
        var edges = new ArrayList<SourceTarget>();
        for (var source : tableLineage.inputTables) {
            edges.add(new SourceTarget(source, tableLineage.outputTable));
        }
        System.out.println(edges);
        return edges;
    }

    public static void main(String[] args) {
        String sql = "INSERT INTO gmall.tableOne SELECT id, name FROM gmall.tableTwo JOIN gmall.tableThree ON gmall.tableTwo.id = gmall.tableThree.id";
        lineage(sql);  // 从two->one  three->one 可以用有向无环图存储
    }
}
